/**
 * 
 */
package com.zufangbao.earth.web.controller.finance;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.demo2do.core.persistence.support.Filter;
import com.demo2do.core.utils.DateUtils;
import com.demo2do.core.utils.StringUtils;
import com.demo2do.core.web.interceptor.MenuSetting;
import com.demo2do.core.web.resolver.Page;
import com.demo2do.core.web.resolver.Secure;
import com.zufangbao.earth.email.excel.TransactionRecordHandler;
import com.zufangbao.earth.entity.security.Principal;
import com.zufangbao.earth.service.PrincipalService;
import com.zufangbao.sun.entity.account.AccountRelation;
import com.zufangbao.sun.entity.account.AccountType;
import com.zufangbao.sun.entity.company.Company;
import com.zufangbao.sun.entity.company.corp.App;
import com.zufangbao.sun.entity.finance.ReportDataGenerator;
import com.zufangbao.sun.entity.icbc.business.AppArriveRecord;
import com.zufangbao.sun.entity.icbc.business.FlowRecord;
import com.zufangbao.sun.entity.order.Order;
import com.zufangbao.sun.entity.order.TransactionRecord;
import com.zufangbao.sun.entity.order.TransactionRecordLog;
import com.zufangbao.sun.entity.order.TransactionRecordStatus;
import com.zufangbao.sun.entity.order.TransactionRecordTitles;
import com.zufangbao.sun.entity.payment.config.PaymentInstitution;
import com.zufangbao.sun.service.AccountRelationService;
import com.zufangbao.sun.service.AppAccountService;
import com.zufangbao.sun.service.AppArriveRecordService;
import com.zufangbao.sun.service.AppService;
import com.zufangbao.sun.service.CompanyService;
import com.zufangbao.sun.service.FlowService;
import com.zufangbao.sun.service.OrderService;
import com.zufangbao.sun.service.PaymentInstitutionService;
import com.zufangbao.sun.service.TransactionRecordLogService;
import com.zufangbao.sun.service.TransactionRecordService;

/**
 * @author mohanlan
 *
 */

@Controller("flowController")
@RequestMapping("/flow")
@MenuSetting("menu-finance")
public class FlowController {

	private static final String APP_ID = "app.id";
	private static final long NOT_EXIST_APP_ID = -1L;
	@Autowired
	private OrderService orderService;
	@Autowired
	private CompanyService companyService;
	@Autowired
	private AppArriveRecordService appArriveRecordService;
	@Autowired
	private AppAccountService appAccountService;
	@Autowired
	private FlowService flowService;
	@Autowired
	private AppService appService;
	@Autowired
	private AccountRelationService accountRelationService;
	@Autowired
	private PaymentInstitutionService paymentInstitutionService;
	@Autowired
	private TransactionRecordHandler transactionRecordHandler;
	@Autowired
	private PrincipalService principalService;
	@Autowired
	private TransactionRecordService transactionRecordService;
	@Autowired
	private TransactionRecordLogService transactionRecordLogService;

	/*
	 * @Value("#{icbcdirectbnkacc['zfb_account_no']}")
	 * 
	 * @Value("#{icbcdirectbnkacc['zfb_account_no']}") private String ZFBAccNo;
	 * 
	 * @Value("#{icbcdirectbnkacc['dingcheng_riskReserve_account_no']}") private
	 * String DCRiskAccNo;
	 */

	/**
	 * return unpaid checking list
	 * 
	 * @return
	 */
	@RequestMapping("/receipt")
	@MenuSetting("submenu-flow-receipt")
	public ModelAndView receipt(Page page, @Secure Principal principal) {

		Filter filter = new Filter();
		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/receipt-history");
		
		List<App> appList=this.principalService.get_can_access_app_list(principal);
		if (!principal.isSuperRole()) {
			filter.addEquals(APP_ID, appList.get(0).getId());
			modelAndView.addObject("app", appList.get(0).getId());
		}
		
		List<TransactionRecord> transactionRecordList = this.getTransactionRecordDataByFilterCondition(filter, page);
		List<PaymentInstitution> paymentInstitutions = this.paymentInstitutionService
				.loadAll(PaymentInstitution.class);
		modelAndView.addObject("role", principal.getAuthority());
		modelAndView.addObject("transactionRecordList", transactionRecordList);
		modelAndView.addObject("appList", appList);
		modelAndView.addObject("paymentModes", paymentInstitutions);
		return modelAndView;

	}

	@RequestMapping("app-receipt")
	@MenuSetting("submenu-app-flow-receipt")
	public ModelAndView appReceipt(Page page, @Secure Principal principal) {

		Filter filter = new Filter();

		if ("ROLE_APP".equals(principal.getAuthority())) {

			filter.addEquals(APP_ID, principal.getKeyId());
		}

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/app-receipt-history");

		com.demo2do.core.persistence.support.Order order = new com.demo2do.core.persistence.support.Order();
		order.add("time", "DESC");

		List<AppArriveRecord> appArriveRecordList = appArriveRecordService
				.list(AppArriveRecord.class, filter, order, page);
		modelAndView.addObject("appArriveRecordList", appArriveRecordList);

		return modelAndView;
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = "/receipt/search", method = RequestMethod.GET, params = "filter")
	@MenuSetting("submenu-flow-receipt")
	public ModelAndView receiptSearch(
			HttpServletRequest request,
			@RequestParam(value = "orderNo", required = false) String orderNo,
			@RequestParam(value = "merchantPaymentNo", required = false) String merchantPaymentNo,
			@RequestParam(value = "startDate", required = false) String startDate,
			@RequestParam(value = "endDate", required = false) String endDate,
			@RequestParam(value = "app_id", required = false) String app_id,
			@RequestParam(value = "paymentMode", required = false) String paymentMode,
			@Secure Principal principal, Page page) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/receipt-history");

		List<App> appList = this.principalService.get_can_access_app_list(principal);
		Filter filter = create_filter_for_user_input(orderNo,
				merchantPaymentNo, startDate, endDate, app_id, paymentMode,
				principal, appList);
		List<TransactionRecord> transactionRecordList = getTransactionRecordDataByFilterCondition(filter,page);
		String queryString = request.getQueryString();
		Map<String, String> queries = StringUtils.parseQueryString(queryString);
		if (queries.containsKey("page")) {
			queries.remove("page");
		}

		List<PaymentInstitution> paymentInstitutions = this.paymentInstitutionService
				.loadAll(PaymentInstitution.class);
		
		modelAndView.addObject("transactionRecordList", transactionRecordList);
		modelAndView.addObject("queryString",
				StringUtils.toQueryString(queries));
		modelAndView.addObject("orderNo", orderNo);
		modelAndView.addObject("role", principal.getAuthority());
		modelAndView.addObject("appList", appList);
		modelAndView.addObject("app", app_id);
		modelAndView.addObject("startDate", startDate);
		modelAndView.addObject("endDate", endDate);
		modelAndView.addObject("merchantPaymentNo", merchantPaymentNo);
		modelAndView.addObject("paymentMode", paymentMode);
		modelAndView.addObject("paymentModes", paymentInstitutions);
		return modelAndView;
	}

	public List<TransactionRecord> injectCustomerPayTimeIntoTransactionRecords(List<TransactionRecord> transactionRecordList){
		for(TransactionRecord transactionRecord : transactionRecordList){
			TransactionRecordLog transactionRecordLog = this.transactionRecordLogService.getTransactionRecordLogByTransactionRecordIdAndStatus(transactionRecord.getId());
			if(transactionRecordLog == null){
				transactionRecord.setCustomerPayTime(transactionRecord.getLastModifiedTime());
			}else{
				transactionRecord.setCustomerPayTime(transactionRecordLog.getModifiedTime());
			}
		}
		return transactionRecordList;
	}
	
	public Filter create_filter_for_user_input(String orderNo,
			String merchantPaymentNo, String startDate, String endDate,
			String app_id, String paymentMode, Principal principal, List<App> appList) {
		Filter filter = createFilterWithAppid(app_id, appList, principal);
		if (is_query_condition(startDate)) {
			filter.addGreaterThan(
					"last_modified_time",
					DateUtils.addDays(
							DateUtils.parseDate(startDate, "yyyy-MM-dd"), 0));
		}
		if (is_query_condition(endDate)) {
			filter.addLessThan(
					"last_modified_time",
					DateUtils.addDays(
							DateUtils.parseDate(endDate, "yyyy-MM-dd"), 1));
		}
		if (is_query_condition(orderNo)) {
			filter.addLike("orderNo", orderNo);
		}
		if (is_query_condition(merchantPaymentNo)) {
			filter.addLike("merchantPaymentNo", merchantPaymentNo);
		}
		if (is_query_condition(paymentMode)) {
			filter.addEquals("paymentInstitution.id", Long.valueOf(paymentMode));
		}
		return filter;
	}
	
	private boolean is_query_condition(String condition){
		return !StringUtils.isEmpty(condition);
	}

	private Filter createFilterWithAppid(String app_id, List<App> appList, Principal princiapl) {
	    Filter filter = new Filter();
	    if (StringUtils.isEmpty(app_id)&& princiapl.isSuperRole()){
	    	return filter;
	    }
	    filter.addEquals(APP_ID, get_query_app_id(app_id, appList));
		return filter;
	}

	private Long get_query_app_id(String app_id, List<App> appList) {
		if (!isValidAppId(app_id, appList)){
			return NOT_EXIST_APP_ID;
		}
		return Long.valueOf(app_id);

	}

	private boolean isValidAppId(String app_id, List<App> appList) {
		for(App app : appList){
			if(is_id_of_the_app(app_id, app)){
				return true;
			}
		}
		return false;
	}

	private boolean is_id_of_the_app(String app_id, App app) {
		return !StringUtils.isEmpty(app_id) && app_id.equals(String.valueOf(app.getId()));
	}


	@RequestMapping(value = "/receipt/result-create-excel", method = RequestMethod.GET)
	public void createExcel(
			HttpServletResponse response,
			HttpServletRequest request,
			@RequestParam(value = "orderNo", required = false) String orderNo,
			@RequestParam(value = "merchantPaymentNo", required = false) String merchantPaymentNo,
			@RequestParam(value = "startDate", required = false) String startDate,
			@RequestParam(value = "endDate", required = false) String endDate,
			@RequestParam(value = "app_id", required = false) String app_id,
			@RequestParam(value = "paymentMode", required = false) String paymentMode,
			@Secure Principal principal) {
		List<App> appList = this.principalService.get_can_access_app_list(principal);
		Filter filter = create_filter_for_user_input(orderNo,
				merchantPaymentNo, startDate, endDate, app_id, paymentMode,
				principal, appList);

        this.createExcelToStream(filter, response);
	}

	public void createExcelToStream(Filter filter,
			HttpServletResponse response) {
		Page allInOnePage = initPageForExcelExport();
		List<TransactionRecord> transactionRecordList = getTransactionRecordDataByFilterCondition(filter,allInOnePage);
		BigDecimal amount = BigDecimal.ZERO;
		List<ReportDataGenerator> reportDataGenerator = new ArrayList<ReportDataGenerator>();
		for (TransactionRecord transactionRecord : transactionRecordList) {
			amount = amount.add(transactionRecord.getPayMoney());
			Order order = this.orderService.getOrder(transactionRecord
					.getOrderNo());
			transactionRecord.setPaymentCustomerName(order.getContract()
					.getCustomer().getName());
			transactionRecord.toReportData();
			reportDataGenerator.add(transactionRecord);
		}
		try {
			response.setContentType("application/vnd.ms-excel");
			response.setHeader("Content-Disposition",
					"attachment;filename=" + java.net.URLEncoder.encode(DateUtils.format(new Date(), "yyyy_MM_dd")+"导出Excel文件"+".xls", "UTF-8"));
			OutputStream out = response.getOutputStream();
			this.transactionRecordHandler.createWorkBook(
					reportDataGenerator, amount,
					TransactionRecordTitles.values(), new Date(), out);
			out.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		

	}

	 Page initPageForExcelExport() {
		Page page = new Page();
		page.setBeginIndex(0);
		page.setCurrentPage(1);
		page.setEveryPage(Integer.MAX_VALUE);
		return page;
	}

	public List<TransactionRecord> getTransactionRecordDataByFilterCondition(
			Filter filter,Page page) {
		com.demo2do.core.persistence.support.Order orderByLastModifyTime = new com.demo2do.core.persistence.support.Order();
		orderByLastModifyTime.add("lastModifiedTime", "DESC");
		List<TransactionRecord> transactionRecordList = this.transactionRecordService
				.list(TransactionRecord.class, filter.addEquals(
						"transactionRecordStatus",
						TransactionRecordStatus.CONFIRMED),
						orderByLastModifyTime,page);
		return injectCustomerPayTimeIntoTransactionRecords(transactionRecordList);
	}

	@RequestMapping(value = "app-receipt/search", method = RequestMethod.GET, params = "app-filter")
	@MenuSetting("submenu-app-flow-receipt")
	public ModelAndView appReceiptSearch(HttpServletRequest request,
			@RequestParam(value = "start") String payStartTime,
			@RequestParam(value = "end") String payEndTime, Page page,
			@Secure Principal principal) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/app-receipt-history");

		Filter filter = new Filter();

		if (principal.getAuthority().equals("ROLE_APP")) {

			filter.addEquals(APP_ID, principal.getKeyId());
		}

		if (!StringUtils.isEmpty(payStartTime)) {
			Date startDate = null;
			try {
				startDate = org.apache.commons.lang.time.DateUtils.parseDate(
						payStartTime, new String[] { "yyyy-MM-dd" });
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			filter.addGreaterThan("time", startDate);
		}
		if (!StringUtils.isEmpty(payEndTime)) {
			Date endDate = null;
			try {
				endDate = org.apache.commons.lang.time.DateUtils.parseDate(
						payEndTime, new String[] { "yyyy-MM-dd" });
				endDate = org.apache.commons.lang.time.DateUtils.addDays(
						endDate, 1);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			filter.addLessThan("time", endDate);
		}
		com.demo2do.core.persistence.support.Order order = new com.demo2do.core.persistence.support.Order();
		order.add("time", "DESC");
		List<AppArriveRecord> appArriveRecordList = appArriveRecordService
				.list(AppArriveRecord.class, filter, order, page);

		String queryString = request.getQueryString();
		Map<String, String> queries = StringUtils.parseQueryString(queryString);
		if (queries.containsKey("page")) {
			queries.remove("page");
		}
		modelAndView.addObject("queryString",
				StringUtils.toQueryString(queries));
		modelAndView.addObject("appArriveRecordList", appArriveRecordList);
		modelAndView.addObject("start", payStartTime);
		modelAndView.addObject("end", payEndTime);

		return modelAndView;
	}

	@RequestMapping("/unpayout")
	@MenuSetting("submenu-flow-unpayout")
	public ModelAndView unpayout(@Secure Principal principal) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/order-unpayout");

		if (principal.getAuthority().equals("ROLE_INSTITUTION")) {
			Company company = companyService.load(Company.class,
					principal.getKeyId());
			List<Order> orderList = orderService
					.queryPaidOrderListByPayeeFactoringCompany(company);
			BigDecimal total = new BigDecimal(0);
			for (Order order : orderList) {
				total = total.add(order.getTotalRent());
			}
			modelAndView.addObject("total", total);
			modelAndView.addObject("orderList", orderList);
		}

		return modelAndView;

	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = "/unpayout/search", method = RequestMethod.GET, params = "filter")
	@MenuSetting("submenu-flow-unpayout")
	public ModelAndView unPayoutSearch(HttpServletRequest request,
			@RequestParam(value = "orderNo", required = false) String orderNo,
			@Secure Principal principal) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/order-unpayout");

		if (principal.getAuthority().equals("ROLE_INSTITUTION")) {
			Company company = companyService.load(Company.class,
					principal.getKeyId());
			List<Order> orderList = orderService
					.queryPaidOrderListByPayeeFactoringCompany(company, orderNo);
			BigDecimal total = new BigDecimal(0);
			for (Order order : orderList) {
				total = total.add(order.getTotalRent());
			}
			modelAndView.addObject("total", total);
			modelAndView.addObject("orderList", orderList);
		}

		modelAndView.addObject("orderNo", orderNo);

		return modelAndView;
	}

	@RequestMapping(value = "/unpayout/print")
	@MenuSetting("submenu-flow-unpayout")
	public ModelAndView showSettlementPrint(
			@RequestParam(value = "orderNo", required = false) String orderNo,
			@Secure Principal principal) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/order-unpayout-print");

		if (principal.getAuthority().equals("ROLE_INSTITUTION")) {
			Company company = companyService.load(Company.class,
					principal.getKeyId());
			List<Order> orderList = orderService
					.queryPaidOrderListByPayeeFactoringCompany(company, orderNo);
			BigDecimal total = new BigDecimal(0);
			for (Order order : orderList) {
				total = total.add(order.getTotalRent());
			}
			modelAndView.addObject("total", total);
			modelAndView.addObject("orderList", orderList);
		}

		modelAndView.addObject("time", new Date());

		return modelAndView;

	}

	@RequestMapping("/monitor")
	@MenuSetting("submenu-flow-monitor")
	public ModelAndView monitor(@Secure Principal principal) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/flow-monitor-today");

		Filter filter = new Filter().addEquals("accountType", AccountType.ZFB);

		List<FlowRecord> flowList = flowService
				.getTodayFlowsByAccount(accountRelationService
						.list(AccountRelation.class, filter).get(0)
						.getAccount());

		List<AccountRelation> AccountRelations = null;
		if(principal.isSuperRole()){
			AccountRelations = getBankAccounts();
		}else{
			AccountRelations = this.accountRelationService.getAccountRelationByCompanyId(4L);
		}

		// modelAndView.addObject("date", DateUtils.format(new Date(),
		// "yyyyMMdd"));
		modelAndView.addObject("accountRelation", 5);
		modelAndView.addObject("flowList", flowList);
		modelAndView.addObject("AccountRelations", AccountRelations);
		modelAndView.addObject("total", cal_total_borrowings(flowList));

		return modelAndView;

	}

	private Map<String, Object> cal_total_borrowings(List<FlowRecord> flowList) {
		Map<String, Object> total = new HashMap<String, Object>();
		BigDecimal debitSum = BigDecimal.ZERO;
		BigDecimal creditSum = BigDecimal.ZERO;

		for (FlowRecord flowRecord : flowList) {

			debitSum = debitSum
					.add(flowRecord.getCreditAmount() == null ? BigDecimal.ZERO
							: flowRecord.getCreditAmount());
			creditSum = creditSum
					.add(flowRecord.getDebitAmount() == null ? BigDecimal.ZERO
							: flowRecord.getDebitAmount());
		}

		total.put("debitSum", debitSum);
		total.put("creditSum", creditSum);

		return total;
	}

	private List<AccountRelation> getBankAccounts() {

		return accountRelationService.loadAll(AccountRelation.class);

	}

	@RequestMapping(value = "/monitor/today/search", method = RequestMethod.GET)
	@MenuSetting("submenu-flow-monitor")
	public ModelAndView flowMonitorSearch(
	// @RequestParam(value = "start", required = false) String startDate,
	// @RequestParam(value = "end", required = false) String endDate,
			@RequestParam(value = "accountRelation") Long accountRelation) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/flow-monitor-today");
		List<AccountRelation> AccountRelations = getBankAccounts();

		List<FlowRecord> flowList = flowService
				.getTodayFlowsByAccount(accountRelationService.load(
						AccountRelation.class, accountRelation).getAccount());

		modelAndView.addObject("flowList", flowList);
		modelAndView.addObject("accountRelation", accountRelation);
		modelAndView.addObject("AccountRelations", AccountRelations);
		modelAndView.addObject("total", cal_total_borrowings(flowList));

		return modelAndView;
	}

	@RequestMapping("/monitor/history")
	@MenuSetting("submenu-flow-monitor")
	public ModelAndView monitorHistory(@Secure Principal principal) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/flow-monitor-history");

		List<AccountRelation> AccountRelations = null;
		if(principal.isSuperRole()){
			AccountRelations = getBankAccounts();
		}else{
			AccountRelations = this.accountRelationService.getAccountRelationByCompanyId(4L);
		}
		// modelAndView.addObject("date", DateUtils.format(new Date(),
		// "yyyyMMdd"));
		modelAndView.addObject("accountRelation", 5);
		modelAndView.addObject("AccountRelations", AccountRelations);

		return modelAndView;

	}

	@RequestMapping(value = "/monitor/history/search", method = RequestMethod.GET)
	@MenuSetting("submenu-flow-monitor")
	public ModelAndView flowHistorySearch(@Secure Principal principal,
			@RequestParam(value = "start", required = false) String startDate,
			@RequestParam(value = "end", required = false) String endDate,
			@RequestParam(value = "accountRelation") Long accountRelation) {
		List<AccountRelation> AccountRelations = null;
		ModelAndView modelAndView = new ModelAndView(
				"finance/flow/flow-monitor-history");
		if(principal.isSuperRole()){
			AccountRelations = getBankAccounts();
		}else{
			AccountRelations = this.accountRelationService.getAccountRelationByCompanyId(4L);
		}
		modelAndView.addObject("AccountRelations", AccountRelations);


		if (startDate.isEmpty() || endDate.isEmpty()) {
			return modelAndView;
		}

		List<FlowRecord> flowList = flowService.getHistoryFlowsByAccount(
				accountRelationService.load(AccountRelation.class,
						accountRelation).getAccount(), startDate, endDate);

		modelAndView.addObject("flowList", flowList);
		modelAndView.addObject("accountRelation", accountRelation);
		modelAndView.addObject("start", startDate);
		modelAndView.addObject("end", endDate);
		modelAndView.addObject("total", cal_total_borrowings(flowList));

		return modelAndView;
	}

}
